# FetchData
# data <- FetchData(object = object, vars = features, slot = slot)

# $ find .  | grep "R$" | xargs grep -n "FetchData" --color=auto
# seurat-object-4.0.4/R/seurat.R:292:FetchData <- function(object, vars, cells = NULL, slot = 'data') {




#' Access cellular data 拿到细胞数据
#'
#' Retrieves data (feature expression, PCA scores, metrics, etc.) for a set
#' of cells in a Seurat object #从Seurat对象中拿到指定细胞的数据：表达值，PCA打分，meta.dta等
#'
#' @param object Seurat object
#' @param vars List of all variables to fetch, use keyword \dQuote{ident} to
#' pull identity classes
#' @param cells Cells to collect data for (default is all cells)
#' @param slot Slot to pull feature data for
#'
#' @return A data frame with cells as rows and cellular data as columns
#'
#' @export
#'
#' @concept data-access
#'
#' @examples
#' pc1 <- FetchData(object = pbmc_small, vars = 'PC_1')
#' head(x = pc1)
#' head(x = FetchData(object = pbmc_small, vars = c('groups', 'ident')))
#'
FetchData <- function(object, vars, cells = NULL, slot = 'data') {
  object <- UpdateSlots(object = object) #重建 Seurat对象
  cells <- cells %||% colnames(x = object) #如果不指定，就取全部细胞

  if (is.numeric(x = cells)) { #如果提供的是细胞编号，则换成cell id
    cells <- colnames(x = object)[cells]
  }

  # Get a list of all objects to search through and their keys
  object.keys <- Key(object = object) #
  #> Key(pbmc_small)
  #  RNA     pca    tsne 
  #"rna_"   "PC_" "tSNE_" 


  # Find all vars that are keyed
  keyed.vars <- lapply(
    X = object.keys,
    FUN = function(key) {
      # 数组长度为0，或者字符串长度为0，返回数字0
      if (length(x = key) == 0 || nchar(x = key) == 0) {
        return(integer(length = 0L))
      }
      # 否则返回输入参数中匹配的系数
      return(grep(pattern = paste0('^', key), x = vars))
    }
  )

  # Filter 高阶函数，把f函数应用到数组x上，结果是TRUE的返回x上原来位置上的元素。
  keyed.vars <- Filter(f = length, x = keyed.vars)
  # 如果 vars=c("PC_1", "tSNE_1", "CD4", "CD8A")，则到这一步时, keyed.vars 是一个list，值是序号，在输入参数中的序号。
  #> keyed.vars
  #$pca
  #[1] 1
  #
  #$tsne
  #[1] 2


  # (A1) 获取数据，从 assay等子对象中
  data.fetched <- lapply(
    X = names(x = keyed.vars), #[1] "pca"  "tsne" 一一进行循环

    FUN = function(x) {
      vars.use <- vars[keyed.vars[[x]]] #根据下标，获取对应的输入参数，比如 "PC_1"
      key.use <- object.keys[x] #获取named vector的value，比如 "PC_"


      # (B1) 如果是 降维 对象
      data.return <- if (inherits(x = object[[x]], what = 'DimReduc')) {

        #再匹配一次，返回匹配到的值，而不是下标
        vars.use <- grep(
          pattern = paste0('^', key.use, '[[:digit:]]+$'),
          x = vars.use,
          value = TRUE
        )

        # 如果长度>0，则尝试获取该对象 的 该属性
        if (length(x = vars.use) > 0) {
          tryCatch(
            #降维类，行名是symbol，这里怎么使用 cells? // todo 可能是错的
            #测试了一下，这么写是对的，需要好好看看[[]]的实现方式了
            expr = object[[x]][[cells, vars.use, drop = FALSE]], # if 中返回的就是这一行，如果没报错
            error = function(...) { #错误处理函数，返回空
              return(NULL)
            }
          )
        } else {
          NULL
        }


      # (B2) 如果是 实验 对象
      } else if (inherits(x = object[[x]], what = 'Assay')) {
        # 这意味着，我们加入了前缀 rna_，否则不会进入这里。
        # 从结果看， "rna_CD8A" 和 "CD8A" 是一样的，但是在函数内的流程是不一样的。
        # 猜测：这个 Key 就是一位了区分 RNA 还是 ATAC
        #df1=FetchData2(pbmc_small, vars=c("PC_1", "tSNE_1", "CD4", "rna_CD8A"))
        vars.use <- gsub(pattern = paste0('^', key.use), replacement = '', x = vars.use) #去掉前缀，"rna_CD8A" to "CD8A"
        
        # 底层就是 slot(pbmc_small@assays$RNA, name = "data")
        data.assay <- GetAssayData(
          object = object,
          slot = slot,
          assay = x
        )

        # 只获取 assay 行名(symbol) 有的基因名字
        vars.use <- vars.use[vars.use %in% rownames(x = data.assay)]

        # 取子集，某些基因、默认全部细胞，然后转置：基因列
        data.vars <- t(x = as.matrix(data.assay[vars.use, cells, drop = FALSE]))

        # 如果列数>0，则把列名(symbol)重新加上前缀
        if (ncol(data.vars) > 0) {
          colnames(x = data.vars) <- paste0(key.use, vars.use)
        }
        data.vars #返回

      # (B3) 如果是 空间图像 对象
      } else if (inherits(x = object[[x]], what = 'SpatialImage')) {
        vars.unkeyed <- gsub(pattern = paste0('^', key.use), replacement = '', x = vars.use) #去掉前缀
        names(x = vars.use) <- vars.unkeyed #获取名字
        coords <- GetTissueCoordinates(object = object[[x]])[cells, vars.unkeyed, drop = FALSE] #获取组织坐标
        colnames(x = coords) <- vars.use[colnames(x = coords)] #?
        coords
      }


      data.return <- as.list(x = as.data.frame(x = data.return))
      return(data.return)
    }

  ) # end of lapply


  data.fetched <- unlist(x = data.fetched, recursive = FALSE) #展开成1行 named vector





  # (A2) Pull vars from object metadata | 从metadata 获取变量
  # 如果 var 在 meta.data 列名中，且不在从 assay 中获取的数据 names() 中
  meta.vars <- vars[vars %in% colnames(x = object[[]]) & !(vars %in% names(x = data.fetched))]

  data.fetched <- c(data.fetched, object[[meta.vars]][cells, , drop = FALSE])# 单列也要保持df结构，这样一列才是一个list。
  
  # 这个获取的是 基因名 中的输入变量
  meta.default <- meta.vars[meta.vars %in% rownames(x = GetAssayData(object = object, slot = slot))]
  
  # 如果有，警告：即是 meata.data，又是基因名
  # 在这里看到 key 的作用了，如果和 meta.data 重名，则返回的是 meta.data；如果想返回 assay中的值，则需要加上 assay的前缀
  if (length(x = meta.default)) {
    warning(
      "The following variables were found in both object metadata and the default assay: ",
      paste0(meta.default, collapse = ", "),
      "\nReturning metadata; if you want the feature, please use the assay's key (eg. ",
      paste0(Key(object = object[[DefaultAssay(object = object)]]), meta.default[1]),
      ")",
      call. = FALSE
    )
  }

  # (A3) Pull vars from the default assay | 从 默认 assay 中获取值
  # 输入参数在 默认基因名中，且不在已经获取的数据的 names() 中
  default.vars <- vars[vars %in% rownames(x = GetAssayData(object = object, slot = slot)) & !(vars %in% names(x = data.fetched))]

  # 直接从 pbmc_small@assays$RNA@data 获取数据，转置为列为symbol，变为df
  data.fetched <- c(
    data.fetched,
    tryCatch(
      expr = as.data.frame(x = t(x = as.matrix(x = GetAssayData(
        object = object,
        slot = slot
      )[default.vars, cells, drop = FALSE]))),
      error = function(...) {
        return(NULL)
      }
    )
  )



  # (A4) Pull identities | 还能获取 ident 信息？
  if ('ident' %in% vars && !'ident' %in% colnames(x = object[[]])) {
    data.fetched[['ident']] <- Idents(object = object)[cells]
  }




  # (A5) Try to find ambiguous vars | 模棱两可的变量
  fetched <- names(x = data.fetched)
  vars.missing <- setdiff(x = vars, y = fetched) #通过差集，得到还未获取的变量

  # 如果有未获取的变量， 在其他 assay 中搜索，看是否有模棱两可的
  if (length(x = vars.missing) > 0) {
    # Search for vars in alternative assays
    vars.alt <- vector(mode = 'list', length = length(x = vars.missing))

    names(x = vars.alt) <- vars.missing
    

    for (assay in FilterObjects(object = object, classes.keep = 'Assay')) {

      vars.assay <- Filter(
        f = function(x) {
          features.assay <- rownames(x = GetAssayData(
            object = object,
            assay = assay,
            slot = slot
          ))
          return(x %in% features.assay) #是否在行名(symbol)中，是了才保留x中对应的原始值
        },
        x = vars.missing
      )

      # 如果在 vars 在某个 assay 的行名中，则把该 assay 记录到 vector 中的该变量list中。
      for (var in vars.assay) {
        vars.alt[[var]] <- append(x = vars.alt[[var]], values = assay)
      }
    }



    # Vars found in multiple alternative assays are truly ambiguous, will not pull
    vars.many <- names(x = Filter(
      f = function(x) {
        return(length(x = x) > 1)
      },
      x = vars.alt
    ))

    # 如果有一个变量出现在超过1个assay的行名中，则警告
    if (length(x = vars.many) > 0) {
      warning(
        "Found the following features in more than one assay, excluding the default. We will not include these in the final data frame: ",
        paste(vars.many, collapse = ', '),
        call. = FALSE,
        immediate. = TRUE
      )
    }

    # 过滤器，不是仅在1个assay中出现的变量名，就认为是丢失了。
    vars.missing <- names(x = Filter(
      f = function(x) {
        return(length(x = x) != 1)
      },
      x = vars.alt
    ))


    # Pull vars found in only one alternative assay | 没有歧义的变量，开始从其他assay中拉取，并作出警告。
    # Key this var to highlight that it was found in an alternate assay

    # 仅出现过一次的变量名
    vars.alt <- Filter(
      f = function(x) {
        return(length(x = x) == 1)
      },
      x = vars.alt
    )

    # 对每个变量循环
    for (var in names(x = vars.alt)) {
      assay <- vars.alt[[var]] #找到对应的assay

      #警告，是从其他assay地方找到的
      warning(
        'Could not find ',
        var,
        ' in the default search locations, found in ',
        assay,
        ' assay instead',
        immediate. = TRUE,
        call. = FALSE
      )

      # 加上 Key 前缀
      keyed.var <- paste0(Key(object = object[[assay]]), var)

      # 使用没有 Key 前缀的 var 获取值，变为一个向量
      data.fetched[[keyed.var]] <- as.vector(
        x = GetAssayData(object = object, assay = assay, slot = slot)[var, cells]
      )

      # 把输入变量 vars 中的 var 替换为 加了Key前缀的var，替换一次，从头到尾精确匹配
      vars <- sub(
        pattern = paste0('^', var, '$'),
        replacement = keyed.var,
        x = vars
      )
    }

    # 已经获取的数据的names。
    fetched <- names(x = data.fetched)
  } # end of A5 的第一个if







  # (A6) Name the vars not found in a warning (or error if no vars found)
  # 找不到的给出警告，一个都没找到则直接error

  # 这是一个警告语句: 如果 vars.missing 超过10个，则警告。否则不警告。
  m2 <- if (length(x = vars.missing) > 10) {
    paste0(' (10 out of ', length(x = vars.missing), ' shown)')
  } else {
    ''
  }

  # 如果一个都没找到的，则报错：
  if (length(x = vars.missing) == length(x = vars)) {
    stop(
      "None of the requested variables were found",
      m2,
      ': ',
      paste(head(x = vars.missing, n = 10L), collapse = ', ')
    )
  # 如果没找到的超过0个，则警告
  } else if (length(x = vars.missing) > 0) {
    warning(
      "The following requested variables were not found",
      m2,
      ': ',
      paste(head(x = vars.missing, n = 10L), collapse = ', ')
    )
  }


  # (A7) Assembled fetched vars in a data frame 
  # 变list为df，指定行名，保持字符串而不是因子
  data.fetched <- as.data.frame(
    x = data.fetched,
    row.names = cells,
    stringsAsFactors = FALSE
  )

  # 拿到 vars 在 fetched 中的位置下标
  data.order <- na.omit(object = pmatch(
    x = vars,
    table = fetched
  ))

  #如果下标长度超过1，就对df的列按下标排序
  if (length(x = data.order) > 1) {
    data.fetched <- data.fetched[, data.order]
  }

  # 再一次命名 列名，这一行是否必要呢？
  colnames(x = data.fetched) <- vars[vars %in% fetched]

  # 返回该数据框
  return(data.fetched)
}




# seurat-object-4.0.4/R/seurat.R:1359:Key.Seurat <- function(object, ...) {
# > Key(object = pbmc_small) # 测试了一下，就是把所有slot为list的
#  RNA     pca    tsne 
# "rna_"   "PC_" "tSNE_"







# /seurat-object-4.0.4/R/generics.R:386:Idents <- function(object, ... ) {
# seurat-object-4.0.4/R/seurat.R:1292:Idents.Seurat <- function(object, ...) {



#' Get, set, and manipulate an object's identity classes
#'
#' @param x,object An object
#' @param ... Arguments passed to other methods; for \code{RenameIdents}: named
#' arguments as \code{old.ident = new.ident}; for \code{ReorderIdent}: arguments
#' passed on to \code{\link{FetchData}}
#'
#' @return \code{Idents}: The cell identities
#'
#' @rdname Idents
#' @export Idents
#'
#' @concept seurat
#'
#' @examples
#' # Get cell identity classes
#' Idents(pbmc_small)
#'
Idents <- function(object, ... ) {
  UseMethod(generic = 'Idents', object = object)
}


#' @rdname Idents
#' @export
#' @method Idents Seurat
#'
Idents.Seurat <- function(object, ...) {
  CheckDots(...)
  object <- UpdateSlots(object = object)
  return(slot(object = object, name = 'active.ident'))
}

# 返回的是就是 pbmc_small@active.ident
#> head(pbmc_small@active.ident)
#ATGCCAGAACGACT CATGGCCTGTGCAT GAACCTGATGAACC TGACTGGATTCTCA AGTCAGACTGCACA TCTGATACACGTGT 
#             0              0              0              0              0              0 
#Levels: 0 1 2






# $ find .  | grep "R$" | xargs grep -n "FilterObjects" --color=auto
# seurat-object-4.0.4/R/seurat.R:518:FilterObjects <- function(object, classes.keep = c('Assay', 'DimReduc')) {
# seurat-4.1.0/R/objects.R:2445:FilterObjects <- function(object, classes.keep = c('Assay', 'DimReduc')) {
# 竟然找到了2个定义！
# 看了一下，函数定义一模一样。只是一个暴露出去，一个内部函数。  为什么要复制粘贴两份呢？完全没必要。



#' Find Sub-objects of a Certain Class
#'
#' Get the names of objects within a \code{Seurat} object that are of a
#' certain class
#'
#' @param object A \code{\link{Seurat}} object
#' @param classes.keep A vector of names of classes to get
#'
#' @return A vector with the names of objects within the \code{Seurat} object
#' that are of class \code{classes.keep}
#'
#' @export
#'
#' @examples
#' FilterObjects(pbmc_small)
#'
FilterObjects <- function(object, classes.keep = c('Assay', 'DimReduc')) {
  object <- UpdateSlots(object = object) #重新生成对象

  # 对obj的slotNames过滤，保留f返回T的 slotNames
  slots <- na.omit(object = Filter(
    f = function(x) {
      # 获取每个slot的内容
      sobj <- slot(object = object, name = x)
      # 该slot是list, 且不是df，且不是版本号，则返回T
      return(is.list(x = sobj) && !is.data.frame(x = sobj) && !is.package_version(x = sobj))
    },
    x = slotNames(x = object)
  ))

  # 去掉 tools 和 misc 这2个 slotNames
  slots <- grep(pattern = 'tools', x = slots, value = TRUE, invert = TRUE)
  slots <- grep(pattern = 'misc', x = slots, value = TRUE, invert = TRUE)

  # 对这些slots循环，获取该slot的值--一个list，获取list中的键名
  # 再解开list，最后就是字符串数组：  "RNA"  "pca"  "tsne"
  slots.objects <- unlist(
    x = lapply(
      X = slots,
      FUN = function(x) {
        return(names(x = slot(object = object, name = x)))
      }
    ),
    use.names = FALSE #不加名字
  )

  #是不是指定的类的对象，返回值是一系列逻辑值，named vector
  object.classes <- sapply(
    X = slots.objects,
    FUN = function(i) {
      return(inherits(x = object[[i]], what = classes.keep)) #pbmc_small[["RNA"]] 是一个对象
    }
  )
  # RNA   pca 
  #TRUE FALSE 
  

  # 给出TRUE值的下标
  object.classes <- which(x = object.classes, useNames = TRUE)
  # RNA 
  #   1

  return(names(x = object.classes))
}



# 测试
> FilterObjects(pbmc_small)
[1] "RNA"  "pca"  "tsne"

> FilterObjects(pbmc_small, classes.keep = "DimReduc")
[1] "pca"  "tsne"

